#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include "rfs-defs.h"

/****************************************************************/
/*  Función que envía un paquete                                */

/****************************************************************/
int enviar(PACKAGE *package) {
    return write(package->to, package, sizeof (PACKAGE));
}

/****************************************************************/
/*  Función que recibe un paquete                               */

/****************************************************************/
int recibir(PACKAGE *package) {
    int n;
    fd_set tmp_set;
    FD_ZERO(&tmp_set);
    FD_SET(package->to, &tmp_set);
    if (select(package->to + 1, &tmp_set, NULL, NULL, NULL) < 0) {
        perror("Error recibiendo paquete.\n");
    } else {
        n = read(package->to, package, sizeof (PACKAGE));
    }
    FD_ZERO(&tmp_set);
    return n;
}

/****************************************************************/
/*  Función que segmenta una cadena en bloques de longitud      */
/*  DATA_LENGTH y los envía                                     */

/****************************************************************/
long segmentar(char * data, PACKAGE * package, unsigned long size) {
    long i = 0;
    for (i = 0; (i * DATA_LENGTH) < size; i++) {
        package->offset = ((i + 1) * DATA_LENGTH) < size ? DATA_LENGTH : (size - (i * DATA_LENGTH));
        memcpy(package->data, &data[i * DATA_LENGTH], package->offset);
        enviar(package);
    }
    return i * DATA_LENGTH + package->offset;
}

/****************************************************************/
/*  Función que ensambla una cadena en bloques de longitud      */
/*  DATA_LENGTH a medida que los recibe                         */

/****************************************************************/
long ensamblar(char ** data, PACKAGE * package) {
    int i = 0;
    do {
        if (recibir(package) < 0)
            return ERROR;
        *data = (char *) realloc(*data, i * DATA_LENGTH + package->offset);
        memmove(&(*data)[i * DATA_LENGTH], package->data, package->offset);
        i++;
    } while (package->offset == DATA_LENGTH);
    return (i - 1)*DATA_LENGTH + package->offset;
};

int create_socket(int port) {

    int sd;
    struct sockaddr_in dir_srv;
    /* Creo un descriptor de archivo. */
    if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        return (-1);

    /* Hago un bind de la direccion local */
    bzero((char *) & dir_srv, sizeof (dir_srv));
    dir_srv.sin_family = AF_INET;
    dir_srv.sin_addr.s_addr = htonl(INADDR_ANY);
    dir_srv.sin_port = htons(port);

    if (bind(sd, (struct sockaddr *) & dir_srv, sizeof (dir_srv)) < 0)
        return (-2);

    listen(sd, MAX_CLIENTS);

    return sd;
}

int close_socket(int sd) {
    return close(sd);
}